﻿/*
   Created 2009 December 13, Randall Maas
   Copyright (c) 2009, Randall Maas
   All rights reserved.

   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions are met:

   Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.

   Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

   Neither the name of Blackwood Designs, LLC nor the names of its contributors
   may be used to endorse or promote products derived from this software without
   specific prior written permission.

   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
   THE POSSIBILITY OF SUCH DAMAGE.
*/

using System;
using System . Drawing;
using System . Drawing . Imaging;


/// <summary>
/// A Sample Grabber delegate that can overlay points on an image
/// (and flip it, as needed).  This is used in conjunction with a LightPaint
/// instance.
/// </summary>
partial class OverlayPoints:ISampleGrabberCB
{
   /// <summary>
   /// The LightPaint delegate that is gathering the pen points
   /// </summary>
   internal LightPaint SrcPoints;

   /// <summary>
   /// Ratio of the source width by our width, scaled (by 1024) to allow for
   /// arithmetic without casting.
   /// </summary>
   int dX2;

   /// <summary>
   /// Ratio of the source height by our height, scaled (by 1024) to allow for
   /// arithmetic without casting.
   /// </summary>
   int dY2;

   /// <summary>
   /// Internal tracking of the size
   /// </summary>
   Size _Size;

   /// <summary>
   /// The size of the image overlay, which must be kept the same as the
   /// node that gets the images and calls this
   /// </summary>
   public Size Size
   {
      get {return _Size;}
      set
      {
         _Size = value;
         Size Size2 = SrcPoints . Size;
         dX2 = (Size2.Width * 1024) / _Size.Width;
         dY2 = (Size2.Height* 1024) / _Size.Height;
      }
   }


   #region The methods needed to support the Sample Grabber Interface
   public int SampleCB(double SampleTime, IntPtr pSample)
   {
      return 0;
   }

   /// <summary>
   /// An internal delegate used to receive each of the image things
   /// </summary>
   /// <param name="SampleTime">The time (since start of graph execution) that
   /// this frame was captured</param>
   /// <param name="Buffer">Pointer to the image buffer</param>
   /// <param name="BufferLen">Size of the buffer, in bytes</param>
   /// <returns>0 (recommended)</returns>
   public int BufferCB(double SampleTime, IntPtr Buffer, int BufferLen)
   {
      unsafe
      {
         // This scary construct speeds up the processing of the buffer a lot
         // by 10ms or more.  This is critical in speeding up access: each frame
         // has to make it thru the whole DS graph in far less than 30ms.
         fixed (byte* CurrentPoint = SrcPoints . CurrentPoints)
         fixed (byte* IsPenPoint   = SrcPoints . IsPoint)
         {
            byte* Buf = (byte*) Buffer;
            byte* End = Buf + BufferLen-(BufferLen%3);

            // The width of the LightPaint delegate and it's size
            int Width2 = SrcPoints . Size . Width;

            // The width of our buffer
            int Width  = Size . Width;

            if (Size == SrcPoints . Size)
              {
                 // This is for the common, but special, case where the LightPaint
                 // delegate and use have the size and we don't need to resize
                 for (int I=0; Buf != End; Buf+=3, I++)
                  if (0 != IsPenPoint[I])
                    {
                       int J = I*3;
                       Buf[0] = CurrentPoint[J++];
                       Buf[1] = CurrentPoint[J++];
                       Buf[2] = CurrentPoint[J++];
                    }
              }
             else
              // The loop used to scan over the points
              // Note: This is designed to allow different sizes for the LightPaint
              // delegate and the buffer we are painting on
              for (int Y = 0, Y2=0; Buf != End; Y2+= dY2, Y=(Y2>>10))
               for (int X=0,J=Y*Width2,I=J*3,I2=Y*Width2*1024;
                    Buf != End && X < Width;
                    X++, Buf+=3, I2+= dX2, J=(I2>>10),I=3*J)
                if (0 != IsPenPoint[J])
                  {
                     Buf[0] = CurrentPoint[I];
                     Buf[1] = CurrentPoint[I+1];
                     Buf[2] = CurrentPoint[I+2];
                  }
         }
      }
      return 0;
   }
   #endregion
}
